﻿using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.Runtime.Session;
using Abp.UI;
using Partner.Surround.Authorization.Roles;
using Partner.Surround.Authorization.Roles.Dto;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Partner.Surround.Authorization.Users.Dto;
using Abp.Organizations;
using Abp.Authorization.Users;
using Partner.Surround.Organizations.Dto;

namespace Partner.Surround.Authorization.Users
{
    /// <summary>
    /// 用户应用服务实现
    /// </summary>
    public class UserAppService : SurroundAppServiceBase, IUserAppService
    {
        #region 初始化
        private readonly UserManager _userManager;
        private readonly RoleManager _roleManager;
        private readonly IRepository<Role> _roleRepository;
        private readonly IPasswordHasher<User> _passwordHasher;
        private readonly IAbpSession _abpSession;
        private readonly LogInManager _logInManager;
        private readonly IRepository<OrganizationUnit, long> _organizationUnitRepository;
        private readonly IRepository<UserOrganizationUnit, long> _userOrganizationUnitRepository;
        private readonly IRepository<UserRole, long> _userRoleRepository;
        private readonly IRepository<User, long> _userRepository;
        private readonly IEnumerable<IPasswordValidator<User>> _passwordValidators;

        public UserAppService(
            UserManager userManager,
            RoleManager roleManager,
            IRepository<Role> roleRepository,
            IPasswordHasher<User> passwordHasher,
            IEnumerable<IPasswordValidator<User>> passwordValidators,
            IAbpSession abpSession,
            LogInManager logInManager,
            IRepository<OrganizationUnit, long> organizationUnitRepository,
            IRepository<UserOrganizationUnit, long> userOrganizationUnitRepository,
            IRepository<UserRole, long> userRoleRepository,
            IRepository<User, long> userRepository)
        {
            _userManager = userManager;
            _roleManager = roleManager;
            _roleRepository = roleRepository;
            _passwordHasher = passwordHasher;
            _passwordValidators = passwordValidators;
            _abpSession = abpSession;
            _logInManager = logInManager;
            _organizationUnitRepository = organizationUnitRepository;
            _userOrganizationUnitRepository = userOrganizationUnitRepository;
            _userRoleRepository = userRoleRepository;
            _userRepository = userRepository;
        }
        #endregion

        #region 用户
        public async Task<GetUserForEditOutput> GetUserForEdit(NullableIdDto<long> input)
        {
            //获取角色列表
            var roleLists = await _roleManager.Roles.OrderBy(r => r.DisplayName).ToListAsync();

            //获取组织机构列表
            var organizationUnitLists = await _organizationUnitRepository.GetAllListAsync();

            var userForEditOutput = new GetUserForEditOutput
            {
                RoleList = ObjectMapper.Map<List<RoleListDto>>(roleLists),
                OrganizationUnitList = ObjectMapper.Map<List<OrganizationUnitListDto>>(organizationUnitLists),
            };

            if (!input.Id.HasValue)  //创建用户
            {
                userForEditOutput.User = new UserEditDto
                {
                    IsActive = true,
                    IsLockoutEnabled = true
                };

                //默认角色列表
                userForEditOutput.RoleNames = await _roleManager.Roles.Where(r => r.IsDefault).Select(r => r.Name).ToListAsync();

                userForEditOutput.MemberedOrganizationUnitIds = new List<long>();
            }
            else  //已存在的用户
            {
                //用户信息
                var user = await UserManager.GetUserByIdAsync(input.Id.Value);
                userForEditOutput.User = ObjectMapper.Map<UserEditDto>(user);

                //用户拥有的角色
                var userRole = await UserManager.GetRolesAsync(user);
                userForEditOutput.RoleNames = userRole.ToList();

                //用户所在的组织机构
                var userOrganizationUnits = await UserManager.GetOrganizationUnitsAsync(user);
                userForEditOutput.MemberedOrganizationUnitIds = userOrganizationUnits.Select(ou => ou.Id).ToList();
            }

            return userForEditOutput;
        }

        public async Task CreateOrUpdateUser(CreateOrUpdateUserInput input)
        {
            if (input.User.Id.HasValue)
                await UpdateUser(input);
            else
                await CreateUser(input);
        }

        [AbpAuthorize(PermissionNames.Pages_Frame_Users_Create)]
        private async Task CreateUser(CreateOrUpdateUserInput input)
        {
            var user = ObjectMapper.Map<User>(input.User);
            user.TenantId = AbpSession.TenantId;
            user.IsEmailConfirmed = true;
            user.Name = "Name";
            user.Surname = "Surname";
            //user.EmailAddress = string.Empty;

            await UserManager.InitializeOptionsAsync(AbpSession.TenantId);
            foreach (var validator in _passwordValidators)
            {
                CheckErrors(await validator.ValidateAsync(UserManager, user, AppConsts.DefaultPassword));
            }

            user.Password = _passwordHasher.HashPassword(user, AppConsts.DefaultPassword);

            await _userManager.InitializeOptionsAsync(AbpSession.TenantId);

            CheckErrors(await _userManager.CreateAsync(user, AppConsts.DefaultPassword));

            if (input.AssignedRoleNames != null)
            {
                CheckErrors(await _userManager.SetRoles(user, input.AssignedRoleNames));
            }

            if (input.OrganizationUnitIds != null)
            {
                await _userManager.SetOrganizationUnitsAsync(user, input.OrganizationUnitIds);
            }

            CurrentUnitOfWork.SaveChanges();
        }

        [AbpAuthorize(PermissionNames.Pages_Frame_Users_Update)]
        private async Task UpdateUser(CreateOrUpdateUserInput input)
        {
            var user = await _userManager.GetUserByIdAsync(input.User.Id.Value);
            ObjectMapper.Map(input.User, user);
            user.SetNormalizedNames();

            CheckErrors(await _userManager.UpdateAsync(user));

            if (input.AssignedRoleNames != null)
            {
                CheckErrors(await _userManager.SetRoles(user, input.AssignedRoleNames));
            }

            if (input.OrganizationUnitIds != null)
            {
                await _userManager.SetOrganizationUnitsAsync(user, input.OrganizationUnitIds);
            }
        }

        [AbpAuthorize(PermissionNames.Pages_Frame_Users_Delete)]
        public async Task DeleteUser(List<EntityDto<long>> inputs)
        {
            foreach (var input in inputs)
            {
                var user = await _userManager.GetUserByIdAsync(input.Id);
                await _userManager.DeleteAsync(user);
            }
        }

        [AbpAuthorize(PermissionNames.Pages_Frame_Users_ResetPassword)]
        public async Task<bool> ResetPassword(ResetPasswordInput input)
        {
            if (_abpSession.UserId == null)
            {
                throw new UserFriendlyException("请先登录系统！");
            }
            long currentUserId = _abpSession.UserId.Value;
            var currentUser = await _userManager.GetUserByIdAsync(currentUserId);
            if (currentUser.IsDeleted || !currentUser.IsActive)
            {
                return false;
            }
            var roles = await _userManager.GetRolesAsync(currentUser);
            if (!roles.Contains(StaticRoleNames.Tenants.Admin))
            {
                throw new UserFriendlyException("只有管理员能够重置密码！.");
            }

            var user = await _userManager.GetUserByIdAsync(input.UserId);
            if (user != null)
            {
                user.Password = _passwordHasher.HashPassword(user, AppConsts.DefaultPassword);
                CurrentUnitOfWork.SaveChanges();
            }

            return true;
        }
        #endregion

        #region 用户与组织机构
        public async Task<PagedResultDto<UserListDto>> GetPagedUser(GetPagedUserInput input)
        {
            IQueryable<User> query = null;
            if (input.OrganizationUnitId.HasValue)
            {
                if (input.OrganizationUnitId < 0)
                {
                    //未分配部门的用户
                    query = from user in _userManager.Users.WhereIf(!input.FilterText.IsNullOrWhiteSpace(), u => u.UserName.Contains(input.FilterText))
                            where !(from uou in _userOrganizationUnitRepository.GetAll() select uou.UserId).Contains(user.Id)
                            select user;
                }
                else
                {
                    //查询指定机构下的用户
                    query = from uou in _userOrganizationUnitRepository.GetAll()
                            join ou in _organizationUnitRepository.GetAll() on uou.OrganizationUnitId equals ou.Id
                            join user in _userManager.Users.WhereIf(!input.FilterText.IsNullOrWhiteSpace(), u => u.UserName.Contains(input.FilterText)) on uou.UserId equals user.Id
                            where uou.OrganizationUnitId == input.OrganizationUnitId
                            select user;
                }
            }
            else
            {
                if (!input.OrganizationUnitIds.IsNullOrWhiteSpace())
                {
                    var organizatonUnitIdList = input.OrganizationUnitIds.Split(",").Select(d => long.Parse(d)).ToList();
                    query = from uou in _userOrganizationUnitRepository.GetAll()
                            join ou in _organizationUnitRepository.GetAll() on uou.OrganizationUnitId equals ou.Id
                            join user in _userManager.Users.WhereIf(!input.FilterText.IsNullOrWhiteSpace(), u => u.UserName.Contains(input.FilterText)) on uou.UserId equals user.Id
                            where organizatonUnitIdList.Contains(uou.OrganizationUnitId)
                            select user;
                }
                else
                {
                    //查询所有用户
                    query = _userManager.Users
                            .WhereIf(input.IsActive.HasValue, u => u.IsActive == input.IsActive)
                            .WhereIf(!input.FilterText.IsNullOrWhiteSpace(), u => u.UserName.Contains(input.FilterText));
                }
            }

            var totalCount = await query.CountAsync();
            var items = await query.PageBy(input).ToListAsync();

            var userListDtos = ObjectMapper.Map<List<UserListDto>>(items);
            await FillRoleNames(userListDtos);

            return new PagedResultDto<UserListDto>(totalCount, userListDtos);
        }
        #endregion

        #region 用户与角色
        private async Task FillRoleNames(IReadOnlyCollection<UserListDto> userListDtos)
        {
            var userRoles = await _userRoleRepository.GetAll()
                .Where(userRole => userListDtos.Any(user => user.Id == userRole.UserId))
                .Select(userRole => userRole).ToListAsync();

            var distinctRoleIds = userRoles.Select(userRole => userRole.RoleId).Distinct();

            foreach (var user in userListDtos)
            {
                var rolesOfUser = userRoles.Where(userRole => userRole.UserId == user.Id).ToList();
                user.Roles = ObjectMapper.Map<List<UserListRoleDto>>(rolesOfUser);
            }

            var roleNames = new Dictionary<int, string>();
            foreach (var roleId in distinctRoleIds)
            {
                var role = await _roleManager.FindByIdAsync(roleId.ToString());
                if (role != null)
                {
                    roleNames[roleId] = role.DisplayName;
                }
            }

            foreach (var userListDto in userListDtos)
            {
                foreach (var userListRoleDto in userListDto.Roles)
                {
                    if (roleNames.ContainsKey(userListRoleDto.RoleId))
                    {
                        userListRoleDto.RoleName = roleNames[userListRoleDto.RoleId];
                    }
                }

                userListDto.Roles = userListDto.Roles.Where(r => r.RoleName != null).OrderBy(r => r.RoleName).ToList();
            }
        }
        #endregion
    }
}

